package com.computer.fundamentals.datastructure;

import com.computer.fundamentals.datastructure.node.DoubleLinkedNode;
import com.computer.util.Constant;
import com.computer.util.UniversalMethod;

public class DoubleLinkedList {

    // 头部哨兵
    public DoubleLinkedNode head;

    // 尾部哨兵
    public DoubleLinkedNode tail;

    public int size;

    public DoubleLinkedList(DoubleLinkedNode head_, DoubleLinkedNode tail_) {
        this.head = head_;
        this.tail = tail_;
        head.next = tail;
        tail.prev = head;
    }

    public void addFirst(int val) {
        DoubleLinkedNode node = new DoubleLinkedNode(val);
        head.next.prev = node;
        node.next = head.next;
        head.next = node;
        node.prev = head;
        size++;
    }

    public void addLast(int val) {
        DoubleLinkedNode node = new DoubleLinkedNode(val);
        tail.prev.next = node;
        node.prev = tail.prev;
        tail.prev = node;
        node.next = tail;
        size++;
    }

    public void removeFirst() {
        if (size <= 0) {
            throw new RuntimeException(Constant.LINKED_LIST_INDEX_OUT_OF_RANGE);
        }
        head.next.next.prev = head;
        head.next = head.next.next;
        size--;
    }

    public void removeLast() {
        if (size <= 0) {
            throw new RuntimeException(Constant.LINKED_LIST_INDEX_OUT_OF_RANGE);
        }
        tail.prev.prev.next = tail;
        tail.prev = tail.prev.prev;
        size--;
    }

    public void insert(int idx, int val_) {
        if (idx > size || idx < 1) {
            throw new RuntimeException(Constant.LINKED_LIST_INDEX_OUT_OF_RANGE);
        }
        DoubleLinkedNode cur = head;
        while (idx > 1) {
            cur = cur.next;
            idx--;
        }
        DoubleLinkedNode newNode = new DoubleLinkedNode(val_);
        cur.next.prev = newNode;
        newNode.next = cur.next;
        cur.next = newNode;
        newNode.prev = cur;
        size++;
    }

    public void remove(int idx) {
        if (size <= 0) {
            throw new RuntimeException(Constant.LINKED_LIST_LENGTH_ZERO);
        }
        DoubleLinkedNode cur = head;
        while (idx > 1) {
            cur = cur.next;
            idx--;
        }
        cur.next.next.prev = cur;
        cur.next = cur.next.next;
        size--;
    }

    public void printLinked() {
        DoubleLinkedNode cur = head.next;
        while (cur != tail) {
            if (cur.next != tail) {
                System.out.print(cur.val + Constant.DOUBLE_LINKED_LIST_SPLIT_SIGNAL);
            } else {
                System.out.print(cur.val);
            }
            cur = cur.next;
        }
    }

    public static void main(String[] args) {
        DoubleLinkedList doubleLinkedList = UniversalMethod.createDoubleLinkedList(Constant.DEFAULT_LINKED_LIST_LENGTH);

        System.out.println("-------------------完整链表-------------------");
        doubleLinkedList.printLinked();
        System.out.println("\n");

        System.out.println("-------------------头插法-------------------");
        doubleLinkedList.addFirst(-1);
        doubleLinkedList.printLinked();
        System.out.println("\n");

        System.out.println("-------------------尾插法-------------------");
        doubleLinkedList.addLast(-1);
        doubleLinkedList.printLinked();
        System.out.println("\n");

        System.out.println("-------------------删除头部节点-------------------");
        doubleLinkedList.removeFirst();
        doubleLinkedList.printLinked();
        System.out.println("\n");

        System.out.println("-------------------删除尾部节点-------------------");
        doubleLinkedList.removeLast();
        doubleLinkedList.printLinked();
        System.out.println("\n");

        System.out.println("-------------------向链表某一个位置插入节点-------------------");
        doubleLinkedList.insert(5, 100);
        doubleLinkedList.printLinked();
        System.out.println("\n");

        System.out.println("-------------------删除某一个位置的节点-------------------");
        doubleLinkedList.remove(5);
        doubleLinkedList.printLinked();
    }
}